package x7.heatctrl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;

/**
 * Manages one Room
 * @author Simon
 *
 */
public class Room {
	private String id;
	private double currentTemp,lastTemp;
	private long lastLog;
	private boolean isHeating;
	
	/** constructor */
	public Room(String id) {
		this.id=id;
	}

	/** returns the id */
	public String getId() { return id; }
	
	/** returns the heating-state */
	public boolean isHeating() { return isHeating;}
	
	/** returns the current temperature as messured in within the last check */
	public double getCurrentTemp() {
	   if (currentTemp==0) updateTemp();
	   return currentTemp;
	}

	/** checks the temperatur of this room */
	public void check() {
		// read Temperature
		updateTemp();
		
		// check temp
		checkGPIO();
	
		// write log to db
		if (System.currentTimeMillis()-lastLog>Config.INSTANCE.getLogInterval()*1000 ) {
			DBFile.INSTANCE.add("insert into templog (Time, Room, Temperature, TargetTemperature, HeatingState, Weather) values ('"+
					currentTimeStamp()+"','"+id+"',"+currentTemp+","+Config.INSTANCE.getTargetTemp(id) +","+(isHeating?1:0)+", (select max(Id) from weather))");
			lastLog = System.currentTimeMillis();
		}
		
	}


	// helper-method for creating a mysql-timestamp
	protected static String currentTimeStamp() {
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());	
	}
	
	// checks if the gpio-state fits the temperatur-check
	private void checkGPIO() {
		GpioPinDigitalOutput pin = Config.INSTANCE.getGPIOPin(id);
		// no pin - no control
		if (pin==null) return;
		
		// read current state, temperatur and target
		isHeating = pin.getState().isLow();
		Boolean setHeating = null;
		double targetTemp = Config.INSTANCE.getTargetTemp(id);
		

		// check if we need to turn on/off the heating
		if (isHeating && currentTemp>targetTemp && (lastTemp>targetTemp || lastTemp==0) ) 
			setHeating=false;
		else if (!isHeating && currentTemp<targetTemp && (lastTemp<targetTemp  || lastTemp==0)) 
			setHeating=true;
	
		// heating is changing
		if (setHeating!=null) {
			// turn on the heating system
			pin.setState(setHeating.booleanValue()?PinState.LOW:PinState.HIGH);
			
			// update last timespan
			DBFile.INSTANCE.add("update heatlog set TimeSpan= TIMESTAMPDIFF(MINUTE,`Time`,'"+currentTimeStamp()+"') " +
					"where Room='"+id+"' order by id desc limit 1");
			
			// insert new Entry
			DBFile.INSTANCE.add("insert into heatlog (Room,State,Time,Temperature,TargetTemperature) values ('"+id+"', "+(isHeating?0:1)+",'"+currentTimeStamp()+"',"+currentTemp+","+targetTemp+")");
			
			// update state
			isHeating = setHeating;
		}
	}

	/** read the temperature from the sensor */
	public void updateTemp() {
		updateTemp(3);
	}
	
	// read the temp using t tries in case of a wrong answer
	private void updateTemp(int t) {
	   BufferedReader fr =null;
	   try {
		   fr= new BufferedReader(new FileReader(Config.INSTANCE.getSensor(id)));
		   String line = fr.readLine();
		   // check if the first line states the correct answer
		   if (line!=null && line.trim().endsWith("NO")) {
			   fr.close();
			   if (t>0) updateTemp(t-1);
			   return;
		   }
		   line = fr.readLine();
		   int pos = line.indexOf("t=");
		   if (pos>0) { 
			   lastTemp = currentTemp;
			   currentTemp =  Integer.parseInt(line.substring(pos+2).trim())/1000.d;
			   if (currentTemp<0) currentTemp=lastTemp;
		   }
		   fr.close();
	   }
	   catch (Exception ex) {
		   if (fr!=null)
				try {
					fr.close();
				} catch (IOException e) {
					Errors.log("Error closeing the temperutefile for "+id+"!", ex);
				}
			Errors.log("Error reading the temperature for "+id+"!", ex);
	   }
	}

}
